标准IO缓冲区与堆区、栈区

若是linux通过setvbuf设置自己的缓冲区buf,若这个buf为与函数栈上,程序可能出现很大的问题,看下面的代码:

#include <stdio.h>
#include <stdlib.h>
FILE *fp;
int setMyBuffer()
{
    char buf[16];
    if ((fp=fopen("data.txt", "r")) == NULL)
    {
        printf("read file failed\n");
        exit(-1);
    }
    setvbuf(fp, buf, _IOFBF, 16);
    return 0;
}
int main()
{
    setMyBuffer();
    char readBuf[32];
    int res;
    res = fread(readBuf, 1, 16, fp);
    readBuf[res] = '\0';
    printf("read buf len is:%d, read buf is:\n%s\n", res, readBuf);
    getchar();getchar();
    return 0;
}

上面这段程序运行时会出现"段错误--Segmentation fault (core dumped)",切记。

“又读又写的情况比较特殊。因为读写缓冲区只有一个,所以在读取内容到缓冲区之前会先把缓冲区里要更新的内容(如果有的话)写到文件。还有一种情况也会引起实际写操作,那就是fseek函数的调用。”

---------------------------------------

位于堆区的,这么说吧,栈区的内存是编译时可确定的。才会在栈区分配内存。io流读进来的数据量没办法确定所以只能在堆区分配空间去存

--------------------------------------------

缓冲区的位置是不确定的,不确定是在堆区还是在栈区。我之前的回答混淆了一个概念,作为警示,就不删除了。

举个读取文件的例子说明问题。在读取文件的时候,使用的是ifstream这个类。但是这个类里面有一个缓冲区。是streambuf类型的。这个缓冲区是可以人为设置的。例如下面这样一个例子

ifstream file("a.txt");

char buf[256] = "buffer";

streambuf * pBuf = file.rdbuf();

pBuf->pubsetbuf(buf, 256);//这里设置缓冲区

上面这段代码的缓冲区就是在栈上面,如果把其中的char buf[256]改成动态new出来的空间,那么缓冲区就是在堆上面了。这才是真相,对于一开始没有深入研究就武断的下结论实在抱歉。

--------------------------------------

标准I/O缓冲区确实是用malloc分配,其初始大小是固定的(linux下可以通过setvbuf设置自己的I/O缓冲区),但原因不是“io流读进来的数据量没办法确定”。举个极端点的例子,用户要一次要fread 512Mbyte的数据,那么按照你的意思,标准I/O函数是不是要malloc一个512Mbytes的内存空间呢?

--------------------------------------

java io包里的缓冲区应该是在堆的,就是个普通的byte数组,nio的缓冲区是调用本地方法分配的直接内存,这样效率更高

--------------------------------------

标准I/O库提供缓冲的目的是尽可能地减少使用read和write系统调用陷入内核的次数,是由C标准I/O库函数来完成这样的缓冲功能,而据了解,标准I/O库通常调用malloc获得需要使用的缓冲区大小。因此,标准I/O缓冲区应该是从堆区分配。

--------------------------------------

为了缓冲区大小的更灵活的动态增长,应该是分配在堆里。

在微软技术库里,找到一篇文章。

**The function printf() takes up 512 bytes from the default heap in 16-bit applications and 4096 bytes in 32-bit applications.

The standard I/O buffer gets allocated only when needed. This gives the program an extra 512 bytes of near-heap space in small and medium memory models or an extra 512 bytes of far-heap space in compact and large models. Therefore, when the printf() function is used for the first time, a 512-byte buffer is reserved for I/O, and the subsequent calls to printf() use that buffer.**

详细参考:

http://support.microsoft.com/kb/44725/en

--------------------------------------

看了前面同学的回答以及一些资料,再总结一下。

I/O 缓冲区是位于哪个地方是可以我们自己决定的,

在默认的情况下,标准 I/O 缓冲区是由系统在堆中申请的一块内存,比如我们常见的的 cin / cout ,或者文件读写的 fstream 等。

但是这些I/O操作我们是可以自己给它设置缓冲区的,如 @__mt同学的答案中的描述,不过这些自定义的缓冲区想要在哪里申请,就自己决定了,可以直接在栈中申请,也可以在堆中申请。

--------------------------------------

确实是在堆区,可以从fread的源码中可以看到。(以windows下的C运行库为例)

fread->_fread_nolock_s->_filbuf->_getbuf()

在_getbuf()中可源代码:

FILE *stream;
/* Try to get a big buffer */
if (stream->_base = _malloc_crt(_INTERNAL_BUFSIZ))
{
    /* Got a big buffer */
    stream->_flag |= _IOMYBUF;
    stream->_bufsiz = _INTERNAL_BUFSIZ;
}

这里_INTERNAL_BUFSIZ=4096;

由此我们可以看到,若用户没有显示设置自己的I/O缓区,那么C运行库的标准I/O程序(如fread)会自动在堆上分配一段大小为4096的缓冲区。

--------------------------------------

其实I/O缓冲区就是系统提供的API里面主动申请的一块内存区,是处于堆上的。所以就需要你在I/O完成之后,关闭I/O流,这样系统API会回收这块内存区。

本页共71段,3099个字符,6138 Byte(字节)